home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / Developer Documentation / Recipes, Tech Notes & Articles / Recipes / Data Interchange / Data Interchange Basics Part 2 < prev    next >
Encoding:
Text File  |  1995-11-07  |  28.8 KB  |  564 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3.  
  4. Data Interchange Basics Part 2
  5. By The OpenDoc Design Team
  6. November 6, 1995
  7.  
  8. © 1993-1995  Apple Computer, Inc. All Rights Reserved.
  9. Apple, the Apple logo, AppleScript, Bento, Macintosh, QuickTime, and OpenDoc are 
  10. registered trademarks of Apple Computer, Inc.
  11. Finder, Mac, and QuickDraw are trademarks of Apple Computer, Inc. 
  12. SOM, SOMObjects, and System Object Model are licensed trademarks of IBM Corporation. 
  13.  
  14.  
  15. Continued from Part 1...
  16.  
  17.  
  18. Writing An Embedded Frame
  19.  
  20. When cloning an embedded frame, your part doesn't add the kODPropContents, kODPropName, or kODPropSuggestedFrameShape properties to the content storage unit.  The kODPropContents property is written by the embedded part in its CloneInto method.  If the embedded part is cooperative, it can be cloned into the content storage unit such that it will promise its content.  The kODPropName property is automatically added by OpenDoc.
  21.  
  22. Instead, your part typically writes three properties: kODPropContentFrame, kODPropProxyContent, and kODPropCloneKindUsed.  Proxy content is optional; if your part doesn't associate any special information with the embedded frame, you don't need to provide it.
  23.  
  24. The recipe below must be followed carefully.  Create a kODPropContentFrame property in the content storage unit, but DO NOT CLONE THE EMBEDDED FRAME YET.  First clone the embedded part, specifying the content storage unit as the destination (this may be the only situation where your part must clone into a specific storage unit).  Then clone the embedded frame, and store a WEAK reference to it into a kODWeakStorageUnitRef value type of the kODPropContentFrame property.  The embedded part must be cloned first; if the embedded frame is cloned first, it will force cloning of the embedded part into a storage unit other than the content storage unit.  The embedded frame should be weakly referenced so it must be explicitly cloned by the destination.
  25.  
  26. To enable the embedded part to fulfill a promise for its content, your part must add a kODPropProxyContent property to the content storage unit.  This property should contain the clone kind specified in the call to BeginClone.
  27.  
  28. Although only an embedded frame is selected, the containing part may associate some intrinsic content with that frame, such as the addition of a drop shadow. After the embedded part is cloned into the content storage unit, the containing part can add a kODPropProxyContent property to the content storage unit to contain whatever intrinsic data it chooses.  If the destination understands the proxy content, the characteristics of the frame will be preserved.
  29.  
  30. When a single embedded frame is written, its important that the content storage unit contain a kODPropContentFrame property.  The presence of this property tells the destination part that the content came from an embedded frame.  According to the OpenDoc Human Interface Guidelines, content cut or copied as an embedded frame should be embedded at the destination, even if the content could be incorporated.  Without the kODPropContentFrame property, the destination part cannot know the content came from an embedded frame.
  31.  
  32. The contentSU argument is the content storage unit of a data interchange object.
  33. The cloneKind parameter specifies the semantics of the operation and is necessary for cloning.
  34. The embeddedFrame parameter is the frame being transferred.
  35. The optional promiseProxyData will be written into each proxy value created by this method in contentSU.
  36.  
  37. void MyCloneEmbeddedFrameToContentSU (Environment *ev,
  38.   ODStorageUnit* contentSU,
  39.   ODCloneKind cloneKind,
  40.   ODFrame* embeddedFrame,
  41.   ODByteArray* promiseProxyData)
  42. {
  43.   // Begin a clone transaction
  44.   ODDraft* myDraft = fSOMSelf->GetStorageUnit(ev)->GetDraft(ev);
  45.   ODDraftKey draftKey = 0;
  46.  
  47.   ODVolatile(myDraft);
  48.   ODVolatile(draftKey);
  49.  
  50.   draftKey = myDraft->BeginClone(ev, contentSU->GetDraft(ev), kODNULL, cloneKind);
  51.  
  52.   TRY
  53.  
  54.     // When transferring one frame, add the content frame property
  55.     //   now but write the value after the embedded part has been cloned.
  56.  
  57.     contentSU->AddProperty(ev, kODPropContentFrame);
  58.  
  59.     // Also add a clone kind used property in case the embedded part promises
  60.     //   its content and thus must perform a clone transaction in its
  61.     //   FulfillPromise method.
  62.  
  63.     ODSetULongProp(ev, contentSU, kODPropCloneKindUsed, kODCloneKind, cloneKind);
  64.  
  65.     // Clone the embedded part into the content storage unit.
  66.     //   If the embedded part is savy, it will notice the kODPropContentFrame
  67.     //   property and promise its content.
  68.  
  69.     ODPart* embeddedPart = embeddedFrame->AcquirePart(ev);
  70.     myDraft->Clone(ev, 
  71.          draftKey,
  72.          embeddedPart->GetID(ev),
  73.          contentSU->GetID(ev),
  74.          embeddedFrame->GetID(ev));
  75.     ODReleaseObject(ev, embeddedPart);
  76.  
  77.     // Clone the embedded frame to the data transfer draft; must be done AFTER
  78.     //   cloning the part because the embedded frame strongly references the part.
  79.  
  80.     ODID toFrameID = myDraft->Clone(ev,
  81.          draftKey,
  82.          embeddedFrame->GetID(ev),
  83.          kODNULLID,
  84.          kODNULLID);    // scope is not relevant for cloning a frame
  85.  
  86.     // Weakly reference the frame so it must be explicitly cloned
  87.     //   into the receiving draft if desired
  88.  
  89.     ODSUForceFocus(ev, contentSU, kODPropContentFrame, kODWeakStorageUnitRef);
  90.     ODStorageUnitRef aSURef = contentSU->GetWeakStorageUnitRef(ev, toFrameID);
  91.     StorageUnitSetValue(contentSU, ev, sizeof(ODStorageUnitRef), &aSURef);
  92.  
  93.     // (Optional) Add proxy content describing the embedded frame
  94.     if ( promiseData )
  95.     {
  96.       ODSUForceFocus(ev, contentSU, kODPropProxyContents, kODNULL);
  97.       contentSU->SetPromiseValue(ev,
  98.           kMyContentKind,
  99.           0,
  100.           promiseProxyData,
  101.           fSOMThis->fPartWrapper);
  102.     }
  103.  
  104.   CATCH_ALL
  105.  
  106.     myDraft->AbortClone(ev, draftKey);
  107.     RERAISE;
  108.  
  109.   ENDTRY
  110.  
  111.   myDraft->EndClone(ev, draftKey);
  112. }
  113.  
  114. Implementing CloneInto
  115.  
  116. Your part may participate in a data interchange operation initiated by some other part.  Specifically, your part may be requested to clone itself into a specified storage unit.  This storage unit may be on the clipboard, in a drag and drop object, or in a link.  Fortunately, it doesn't matter to your part, as long as your part clones itself correctly.
  117.  
  118. First, your part should not implement CloneInto by calling  its Externalize method and then cloning its storage unit into the specified storage unit.  Externalizing your part may require writing to disk; if every part did this in response to CloneInto performance would suffer.  Also, your Externalize method doesn't take the scope frame into account.  For example, a display frame of your part may have been cut but not yet removed, and your part shouldn’t include this as a display frame when it clones itself into a storage unit.
  119.  
  120. Your part's CloneInto method should only add and write to the kODPropContents property.  OpenDoc will copy the part name and other annotations automatically.
  121.  
  122. Your part's CloneInto method also should not start a clone transaction by calling BeginClone.  One will have already been started by the part initiating the operation.
  123.  
  124. When CloneInto Should Write a Promise
  125.  
  126. To enable quick response when the user initiates dragging a frame, all parts should be able to promise their content  when their CloneInto method is called.  CloneInto should check for the presence of the kODPropContentFrame property.  This property will only be present if the part is being cloned into a content storage unit by a containing part.  In this situation only, a part can promise its content instead of actually copying data.  IN OTHER SITUATIONS YOUR PART MUST WRITE ACTUAL DATA!  Your part’s CloneInto method may be called when another part is fulfilling a promise, and your part must not promise content in this case.
  127.  
  128. The promise data written should identify the display frame of this part specified in the scopeFrame parameter to CloneInto, to allow the part's FulfillPromise method to deliver the correct content.  Note that CloneInto may be called multiple times, possibly with different scopeFrame parameters.
  129.  
  130. SOM_Scope void  SOMLINK MyPartCloneInto(MyPart *somSelf, Environment *ev,
  131.   ODDraftKey key,
  132.   ODStorageUnit* storageUnit,
  133.   ODFrame* scopeFrame)
  134. {
  135.   MyPartData *somThis = MyPartGetData(somSelf);
  136.   MyPartMethodDebug("MyPart","CloneInto");
  137.  
  138.   // First check for the existence of my content kind; if the value is present, 
  139.   //   this part has already been cloned (but respect scopeFrame which could 
  140.   //   include more that was previously cloned; for simple parts this won't make a difference)
  141.   if ( !storageUnit->Exists(ev, kODPropContents, kMyContentKind, 0) )
  142.   {
  143.     SOM_TRY
  144.     
  145.       parent_CloneInto(somSelf, ev, key, storageUnit, scopeFrame);
  146.  
  147.       // Focus to the contents property, adding if necessary
  148.       ODSUForceFocus(ev, storageUnit, kODPropContents, kODNULL);
  149.  
  150.       // Optional - Check to see if the content can be promised
  151.       if ( storageUnit->Exists(ev, kODPropContentFrame, kODNULL, 0) )
  152.       {
  153.         // Placeholders to be replaced by part-specific data
  154.         ODByteArray promiseData = CreateByteArrayStruct(kODNULL,0);
  155.  
  156.         // Write a promise for each content kind
  157.         storageUnit->SetPromiseValue(ev, kMyContentKind, 0, &promiseData, somThis->fPartWrapper);
  158.  
  159.         // Promise other content kinds
  160.         storageUnit->SetPromiseValue(ev, isoTypeAppleScrapText, 0, &promiseData, somThis->fPartWrapper);
  161.  
  162.         DisposeByteArrayStruct(promiseData);
  163.       }
  164.       else
  165.       {
  166.         // Placeholders to be replaced by part-specific data
  167.         ODByteArray myContentKindData = CreateByteArrayStruct(kODNULL,0);
  168.         ODByteArray textContentKindData = CreateByteArrayStruct(kODNULL,0);
  169.  
  170.         // Add content kinds in this part's fidelity order
  171.         ODSUForceFocus(ev, storageUnit, kODPropContents, kMyContentKind);
  172.         storageUnit->SetValue(ev, &myContentKindData);
  173.  
  174.         ODSUForceFocus(ev, storageUnit, kODPropContents, isoTypeAppleScrapText);
  175.         storageUnit->SetValue(ev, &textContentKindData);
  176.  
  177.         DisposeByteArrayStruct(myContentKindData);
  178.         DisposeByteArrayStruct(textContentKindData);
  179.       }
  180.  
  181.     SOM_CATCH_ALL
  182.     
  183.     SOM_ENDTRY
  184.   }
  185. }
  186.  
  187. Notes on CloneInto When Called to Write to a Link
  188.  
  189. Parts must be aware that links are never cloned into a link.  Parts that write content directly into a link they maintain, or parts who’s CloneInto method is called to write content into a link, must handle cloning of link objects as described in the next paragraph.  A part’s CloneInto method doesn’t know when the destination storage unit is in a link, so it must follow this recipe all the time.
  190.  
  191. If a part calls its draft's Clone method on a link or link source object, and the destination of the clone is a link, Clone will return the object ID kODNULLID.  Clone returns kODNULLID when the object is not cloned. Attempting to call a storage unit's GetStrongStorageUnitRef with a null object id will cause an exception to be returned.  A part should check the result of Clone by calling ODDraft::IsValidID; if IsValidID returns kODFalse, it should write unlinked content only.  In most cases, the part will simply not write out the link or link source object reference and whatever other data it associates with the link.
  192.  
  193. Note that if a part has not been internalized, it may be cloned into a link via its storage unit’s CloneInto method.  Any references to link or link source objects from the storage unit will be copied but won’t be valid because the referenced objects won’t be cloned.  Parts must always validate persistent references to link and link source objects before internalizing them in their InitPartFromStorage method, and abandon the link if the reference is invalid.
  194.  
  195. Incorporating from a Content Storage Unit
  196.  
  197. This recipe demonstrates how data may be incorporated from a content storage unit.
  198.  
  199. To incorporate content, read a value type from the kODPropContents property of the content storage unit.  Each storage unit referenced from the value stream should be cloned to the receiving part's draft.  The part performing the clone must not internalize objects from cloned storage units until EndClone is called; if the clone has to be aborted for any reason, the storage units will be removed from the draft.
  200.  
  201. Each frame embedded during incorporation must have their containing frame, link status, and in-limbo fields set correctly.  In addition, the previous in-limbo setting of each frame must be remembered for use during  undo.
  202.  
  203. Each frame embedded must be inserted into the receiving part's frame hierarchy by calling the embedded frame's SetContainingFrame method.  SetContainingFrame must be called after EndClone since it is illegal to internalize a frame until a cloning transaction successfully completes.  SetContainingFrame must be called before the part displayed in the frame is internalized by calling AcquirePart.  Internalizing the part causes DisplayFrameConnected to be called. The activation recipe (applied to the embedded part) specifies that the frame should become active if its a root frame, that is, its containing frame is null.  The embedded frame won't have a containing frame until one is set by the part perfoming the incorporation.
  204.  
  205. If the embedded frame should appear in other display frames of the receiving part, additional embedded frames need to be created.  The reader is referred to the Layout recipes for more details on embedding.
  206.  
  207. Each frame embedded must have its  link status set by calling its ChangeLinkStatus method.  All parts must set the link status of their embedded frames, even parts that don't otherwise support linking.  Parts that support linking are referred to the Linking recipes for more information on setting link status.  Parts that don't support linking should set all embedded frames to kODNotInLink.
  208.  
  209. This recipe incorporates the part’s native content kind, kMyContentKind, from the content storage unit.  Unless the user specifies a type to incorporate in the Paste As dialog, the part should incorporate the highest fidelity kind that it supports.  This may not be the first kind in the kODPropContents property, nor may it be the part's native representation.  The native content kind is incorporated here for simplicity.
  210.  
  211. The contentSU argument is the content storage unit of the data interchange object to incorporate from.
  212. The targetFrame argument identifies the frame being incorporated into and is passed to BeginClone.
  213. The cloneKind argument specifies the semantics of the operation and is passed to BeginClone.
  214. The embeddedFrameLinkStatus argument is used to set the link status of frames embedded from contentSU.
  215.  
  216. SOM_Scope void  SOMLINK MyPartMyReadFromContentSU(MyPart *somSelf, Environment *ev,
  217.   ODStorageUnit* contentSU,
  218.   ODFrame* targetFrame,
  219.   ODCloneKind cloneKind,
  220.   ODLinkStatus embeddedFrameLinkStatus)
  221. {
  222.   MyPartData *somThis = MyPartGetData(somSelf);
  223.   MyPartMethodDebug("MyPart","MyReadFromContentSU");
  224.  
  225.   // Placeholders to be replaced by part-specific data
  226.   ODByteArray data = CreateByteArrayStruct(kODNULL,0);
  227.   ODStorageUnitRef aStrongRef;
  228.   ODID strongClonedID = kODNULLID;
  229.   ODID weakClonedID = kODNULLID;
  230.  
  231.   // Begin a clone transaction
  232.   ODDraft* myDraft = somSelf->GetStorageUnit(ev)->GetDraft(ev);
  233.   ODDraftKey draftKey = 0;
  234.  
  235.   ODVolatile(myDraft);
  236.   ODVolatile(draftKey);
  237.  
  238.   SOM_TRY
  239.     
  240.     draftKey = myDraft->BeginClone(ev, contentSU->GetDraft(ev), targetFrame, cloneKind);
  241.  
  242.     TRY
  243.     
  244.       // For simplicity, this example code incorporates kMyContentKind.
  245.       //   A real part should examine the content kinds present in fidelity order and
  246.       //   read the best kind it supports.
  247.       contentSU->Focus(ev, kODPropContents, kODPosUndefined, kMyContentKind, 0, kODPosUndefined);
  248.  
  249.       // For demonstration, read the data into an ODByteArray.
  250.       contentSU->GetValue(ev, contentSU->GetSize(ev), &data);
  251.       
  252.       // Usually, the data will reference other storage units.  These objects need to be
  253.       //   cloned into this part's draft.  You must wait until EndClone completes without
  254.       //   error to turn strongClonedID into a persistent object.  If strongClonedID is
  255.       //   valid, you may create a storage unit reference to it, but beware that the reference
  256.       //   may become invalid after EndClone or AbortClone is called.
  257.       strongClonedID = somSelf->MyCloneStrongReference(ev, contentSU, aStrongRef, draftKey);
  258.  
  259.       // Your part must distinguish between references that are strong and references that
  260.       //   are weak, and clone them accordingly.
  261.       weakClonedID = somSelf->MyCloneWeakReference(ev, contentSU, aStrongRef, draftKey);
  262.  
  263.     CATCH_ALL
  264.  
  265.       myDraft->AbortClone(ev, draftKey);
  266.       RERAISE;
  267.  
  268.     ENDTRY
  269.  
  270.     myDraft->EndClone(ev, draftKey);
  271.     
  272.     // Now incorporate the read data & cloned objects into this part's content
  273.     if ( myDraft->IsValidID(ev, strongClonedID) )
  274.     {
  275.         // Safe to internalize the cloned object.  As an example, the object's
  276.         //   storage unit is acquired and released here.
  277.         ODStorageUnit* su = myDraft->AcquireStorageUnit(ev, strongClonedID);
  278.         su->Release(ev);
  279.     }
  280.     else
  281.     {
  282.         // The object wasn't sucessfully cloned, so exclude it from this part's content
  283.     }
  284.  
  285.     // If the incorporated content contains embedded frames, you must ensure certain
  286.     //   frame characteristics are set properly.  Be sure to call SetContainingFrame
  287.     //   before the embedded part is internalized.  Also, this part must remember the 
  288.     //   in-limbo status of each embedded frame in its undo action data to implement 
  289.     //   undo correctly.
  290.     ODBoolean embeddedFrameWasInLimbo = embeddedFrame->IsInLimbo(ev);
  291.     embeddedFrame->SetInLimbo(ev, kODFalse);
  292.     embeddedFrame->SetContainingFrame(ev, targetFrame);
  293.     embeddedFrame->ChangeLinkStatus(ev, embeddedFrameLinkStatus);
  294.  
  295.   SOM_CATCH_ALL
  296.     
  297.   SOM_ENDTRY
  298.   
  299.   DisposeByteArrayStruct(data);
  300. }
  301.  
  302. Embedding a Content Storage Unit
  303.  
  304. This example demonstrates how  a content storage unit can be embedded as a part.  To embed the content storage unit, the part performing the transfer clones the content storage unit into the part's draft.  If the content storage unit also contains a kODPropContentFrame property, the storage unit referenced by that property should be explicitly cloned into the part's draft.  The frame storage unit must be explicitly cloned because it is only weakly referenced by the content storage unit, and would otherwise not be cloned.
  305.  
  306. If a frame was provided, the receiving part should call that frame's SetContainingFrame method, passing in the display frame of the active facet.  Be sure to call SetContainingFrame before the embedded part is internalized by calling AcquirePart.  If no frame was provided, the receiving part should create an embedded frame, using the frame shape specified by the kODPropSuggestedFrameShape property, if present.  In either case, for each visible embedded frame, the receiving part should create facets by calling the CreateEmbeddedFacets method of the display frame of the active facet.
  307.  
  308. The contentSU argument is the content storage unit of the data interchange object to embed.
  309. The targetFrame argument identifies the frame being incorporated into and is passed to BeginClone.
  310. The cloneKind argument specifies the semantics of the operation and is passed to BeginClone.
  311. The embeddedFrameLinkStatus argument is used to set the link status of the embedded frame.
  312.  
  313. SOM_Scope void  SOMLINK MyPartMyEmbedContentSU(MyPart *somSelf, Environment *ev,
  314.   ODStorageUnit* contentSU,
  315.   ODFrame* targetFrame,
  316.   ODCloneKind cloneKind,
  317.   ODLinkStatus embeddedFrameLinkStatus)
  318.  
  319. {
  320.   MyPartData *somThis = MyPartGetData(somSelf);
  321.   MyPartMethodDebug("MyPart","MyEmbedContentSU");
  322.  
  323.   ODDraft* contentSUDraft = contentSU->GetDraft(ev);
  324.   ODDraft* myDraft = somSelf->GetStorageUnit(ev)->GetDraft(ev);
  325.  
  326.   ODDraftKey draftKey = 0;
  327.   ODID embeddedFrameID = kODNULLID;
  328.   ODID embeddedPartID = kODNULLID;
  329.  
  330.   ODPart* embeddedPart = kODNULL;
  331.   ODFrame* embeddedFrame = kODNULL;
  332.  
  333.   // This part must remember the in-limbo status of the embedded frame in its
  334.   //   undo action data to implement undo correctly.
  335.   ODBoolean embeddedFrameWasInLimbo = kODTrue;
  336.  
  337.   // Placeholders to be replaced by part-specific data
  338.   ODByteArray proxyData = CreateByteArrayStruct(kODNULL,0);
  339.  
  340.   ODVolatile(contentSUDraft);
  341.   ODVolatile(draftKey);
  342.  
  343.   SOM_TRY
  344.  
  345.     // Begin a clone transaction into this draft.
  346.     draftKey = contentSUDraft->BeginClone(ev, myDraft, targetFrame, cloneKind);
  347.  
  348.     TRY
  349.     
  350.       // Clone the content storage unit
  351.       //   The scopeID kODNULLID indicates the clone is not restricted to a particular frame context.
  352.       embeddedPartID = contentSUDraft->Clone(ev, draftKey, contentSU->GetID(ev), kODNULLID, kODNULLID);
  353.  
  354.       // If a content frame is present, clone it, too
  355.       if ( ODSUExistsThenFocus(ev, contentSU, kODPropContentFrame, kODWeakStorageUnitRef) )
  356.       {
  357.         ODStorageUnitRef aSURef;
  358.         StorageUnitGetValue(contentSU, ev, sizeof(ODStorageUnitRef), &aSURef);
  359.         embeddedFrameID = somSelf->CloneStrongReference(ev, contentSU, aSURef, draftKey);
  360.       }
  361.  
  362.       // Read proxy content if present.
  363.       if ( ODSUExistsThenFocus(ev, contentSU, kODPropProxyContents, kMyContentKind) )
  364.       {
  365.         // For demonstration, read the data into an ODByteArray.
  366.         //   Note that this may contain storage unit references, such as to an ODLink 
  367.         //   or ODLinkSource storage unit, so cloning may be necessary here.
  368.         contentSU->GetValue(ev, contentSU->GetSize(ev), &proxyData);
  369.       }
  370.  
  371.     CATCH_ALL
  372.  
  373.       contentSUDraft->AbortClone(ev, draftKey);
  374.       RERAISE;
  375.  
  376.     ENDTRY
  377.  
  378.     contentSUDraft->EndClone(ev, draftKey);
  379.  
  380.     if ( myDraft->IsValidID(ev, embeddedFrameID) )
  381.     {
  382.       embeddedFrame = myDraft->AcquireFrame(ev, embeddedFrameID);
  383.       embeddedFrameWasInLimbo = embeddedFrame->IsInLimbo(ev);
  384.       embeddedFrame->SetInLimbo(ev, kODFalse);
  385.       embeddedFrame->SetDragging(ev, kODFalse); // In case the frame was dropped
  386.       embeddedFrame->SetContainingFrame(ev, targetFrame);
  387.     }
  388.     else
  389.     {
  390.       // Create a new embedded frame for newPart, using the suggested frame shape
  391.       //   if present.
  392.       TempODShape newShape = NULL;
  393.       
  394.       if ( ODSUExistsThenFocus(ev, contentSU, kODPropSuggestedFrameShape, kODNULL) )
  395.       {
  396.         newShape = targetFrame->CreateShape(ev);
  397.         newShape->ReadShape(ev, contentSU);
  398.       }
  399.       
  400.       // Acquire the new embedded part
  401.       TempODPart embeddedPart = myDraft->AcquirePart(ev, embeddedPartID);
  402.  
  403.       // Use my method to create an embedded frame of the desired shape
  404.       embeddedFrame = somSelf->MyMakeEmbeddedFrame(ev, targetFrame, newShape, embeddedPart);
  405.     }
  406.  
  407.     // Set the link status of the embedded frame
  408.     embeddedFrame->ChangeLinkStatus(ev, embeddedFrameLinkStatus);
  409.  
  410.     // Add the embedded frame and proxy content to this part's content
  411.     //…
  412.  
  413.     // Now add facets to display the newFrame
  414.     //…
  415.  
  416.   SOM_CATCH_ALL
  417.     
  418.   SOM_ENDTRY
  419. }
  420.  
  421. Creating an Embedded Frame
  422.  
  423. This example demonstrates how a part could make a new frame for a part embedded from a content storage unit.  This is mostly a wrapper around ODDraft::CreateFrame.
  424.  
  425. The containingFrame argument is the frame to contain the new embedded frame.
  426. The frameShape argument is the desired shape or null to use a default shape.
  427. The embeddedPart argument is the part to be displayed by the embedded frame.
  428.  
  429. SOM_Scope ODFrame*  SOMLINK MyPartMyMakeEmbeddedFrame(MyPart *somSelf, Environment *ev,
  430.   ODFrame* containingFrame,
  431.   ODShape* frameShape,
  432.   ODPart* embeddedPart)
  433. {
  434.   MyPartData *somThis = MyPartGetData(somSelf);
  435.   MyPartMethodDebug("MyPart","MyMakeEmbeddedFrame");
  436.  
  437.   const ODBoolean notRoot = kODFalse;
  438.   const ODBoolean notOverlaid = kODFalse;
  439.   ODCanvas* nullCanvas = (ODCanvas*) kODNULL;
  440.  
  441.   ODFrame* embeddedFrame = kODNULL;
  442.   TempODShape newShape = kODNULL;  // Automatically released
  443.   
  444.   SOM_TRY
  445.  
  446.     if ( frameShape )
  447.     {
  448.       newShape = frameShape;
  449.       newShape->Acquire(ev);
  450.     }
  451.     else
  452.     {
  453.       // No suggested frame shape, so use a default size
  454.       ODRect rect;
  455.       rect.SetInt(0,0,80,80);
  456.       newShape = containingFrame->CreateShape(ev);
  457.       newShape->SetRectangle(ev, &rect);
  458.     }
  459.  
  460.     embeddedFrame = somSelf->GetStorageUnit(ev)->GetDraft(ev)->CreateFrame(ev, 
  461.                         kODFrameObject, 
  462.                         containingFrame, 
  463.                         newShape, 
  464.                         nullCanvas,
  465.                         embeddedPart,
  466.                         _fSession->Tokenize(ev, kODViewAsFrame),
  467.                         _fSession->Tokenize(ev, kODPresDefault),
  468.                         notRoot,
  469.                         notOverlaid);
  470.   SOM_CATCH_ALL
  471.     
  472.   SOM_ENDTRY
  473.  
  474.   return embeddedFrame;
  475. }
  476.  
  477. The Paste As Dialog
  478.  
  479. Two data interchange objects, the clipboard and the drag and drop object, have a ShowPasteAsDialog method that present a dialog allowing the user to specify options on paste or drop.
  480.  
  481. The ODPasteAsMergeSetting parameter to ShowPasteAsDialog specifies whether "Merge with Contents" or "Embed as" is initially chosen, and whether the other choice is available.  This parameter allows the Paste As dialog to default to the same behavior your part uses on Paste.  Specify this parameter using one of these ODPasteAsMergeSetting values:
  482.  
  483. kODPasteAsMerge - "Merge with Contents" is initially selected; "Embed as" allowed.  Specify this constant if your part can incorporate one of the kinds in the content storage unit, and your part supports embedding.
  484.  
  485. kODPasteAsEmbed - "Embed as" is initially selected; "Merge with Contents" is allowed.   Specify this constant if your part can incorporate one of the kinds in the content storage unit, but your part would prefer to embed it.  This is the case if incorporation would result in a loss of fidelity, or if the content storage unit was created by copying a single embedded frame (that is, the content storage unit contains a kODPropContentFrame property).
  486.  
  487. kODPasteAsMergeOnly - "Embed as" is disabled.  Specify this constant if your part doesn't support embedding, and your part can incorporate one of the kinds in the content storage unit, possibly translated.
  488.  
  489. kODPasteAsEmbedOnly - "Merge with Contents" is disabled.  Specify this constant if your part supports embedding, and no kind in the content storage unit can be incorporated, even after translation.
  490.  
  491. The ShowPasteAsDialog method returns its results in the ODPasteAsResult parameter.  If ShowPasteAsDialog returns kODTrue, your part is responsible for disposing the selectedKind, translateKind, and editor fields of this structure.  ShowPasteAsDialog will set any unspecified fields to nil.
  492.  
  493. Embedding a Part via the Paste As Dialog 
  494.  
  495. When a part is embedded via the Paste As dialog, the user can specify a particular content kind or request translation to another kind.  In addition, the user may specify the editor to bind to the embedded part.  The caller of ShowPasteAsDialog must perform a few simple steps to ensure these choices are followed.  This example uses the ShowPasteAsDialog method of the clipboard object.
  496.  
  497. ODPasteAsResult pasteAsResult;
  498.  
  499. // Parameters except pasteAsResult are omitted
  500. if ( clipboard->ShowPasteAsDialog(…, &pasteAsResult) )
  501. {
  502.   if ( pasteAsResult.mergeSetting == kODFalse )
  503.   {
  504.     // Clone the root storage unit from the clipboard as demonstrated
  505.     //   in the general embedding recipe above
  506.     key = clipDraft->BeginClone(…);
  507.     newPartID = clipDraft->Clone(…)
  508.     …
  509.     clipDraft->EndClone(…);
  510.  
  511.     // Acquire the newly embedded storage unit
  512.     ODStorageUnit* newSU = myDraft->AcquireStorageUnit(ev, newPartID);
  513.  
  514.     if ( pasteAsResult.translateKind != kODNULL )
  515.     {
  516.       // Translation was requested from translateKind to selectedKind
  517.       // Add selectedKind and create the to storage unit view
  518.       ODSUForceFocus(ev, newSU, kODPropContents, pasteAsResult.selectedKind);
  519.       ODStorageUnitView* toView = newSU->CreateView(ev);
  520.  
  521.       // Create the from storage unit view
  522.       newSU->Focus(ev, kODPropContents, kODPosUndefined, pasteAsResult.translateKind, 0, kODPosUndefined);
  523.       ODStorageUnitView* fromView = newSU->CreateView(ev);
  524.  
  525.       // Get the translation object and perform the translation
  526.       ODTranslation* translation = mySession->GetTranslation(ev);
  527.       ODTranslateResult translatResult = translation->TranslateView(ev, fromView, toView);
  528.  
  529.       // Check for sucessful translation
  530.       …
  531.  
  532.       // Clean up after translation
  533.       toView->Release(ev);
  534.       fromView->Release(ev);
  535.     }
  536.  
  537.     // Set the preferred kind
  538.     ODSetISOStrProp(ev, contentSU, kODPropPreferredKind, kODISOStr, pasteAsResult.selectedKind);
  539.  
  540.     // Set the preferred editor
  541.     if ( pasteAsResult.editor != kODNoEditor )
  542.     {
  543.       ODSetISOStrProp(ev, contentSU, kODPropPreferredEditor, kODEditor, pasteAsResult.editor);
  544.     }
  545.  
  546.     // Release the storage unit
  547.     newSU->Release(ev);
  548.   }
  549. }
  550.  
  551. // Complete embedding of the part
  552.  
  553. // When finished with pasteAsResult, be sure to dispose of the
  554. //   selectedKind ,translateKind, and editor fields.
  555. if ( pasteAsResult.selectedKind != kODNULL )
  556.   DisposePtr(pasteAsResult.selectedKind )
  557.  
  558. if ( pasteAsResult.translateKind != kODNULL )
  559.   DisposePtr(pasteAsResult.translateKind )
  560.  
  561. if ( pasteAsResult.editor != kODNULL ) 
  562.   DisposePtr(pasteAsResult.editor )
  563.